// Copyright (c) 2009 Mike Haight, Andy Kipp
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

#include "stdafx.h"

using namespace System::IO;
using namespace System::Xml;
using namespace System::Xml::Serialization;

World::World() 
{
}

String^ World::Name::get(void) 
{
    return mName;
}


Coordinates::Size World::Size::get(void)
{
    return mSize;
}


Dictionary<String^, Layer^>^ World::Layers::get(void)
{
    return %mLayers;
}


Dictionary<String^, Quest^>^ World::Quests::get(void)
{
    return %mQuests;
}


Dictionary<String^, WorldObject^>^ World::Objects::get(void)
{
    return %mObjects;
}


List<WorldObject^>^ World::GetObjects(Coordinates::Rectangle argRectangle)
{
    List<WorldObject^>^ objects = gcnew List<WorldObject^>();
    for each (WorldObject^ obj in mObjects.Values)
        if (argRectangle.Contains(obj->Location))
            objects->Add(obj);
    return objects;
}


void World::ReadXml(XmlReader^ reader) 
{
    // Create Document
    XmlDocument^ doc = gcnew XmlDocument();
    doc->Load(reader);

    // Get World Element
    XmlElement^ worldElement = doc->DocumentElement;

    // Get World Element Attributs
    mName = worldElement->GetAttribute("Name");
    mSize.Height = (float)Int32::Parse(worldElement->GetAttribute("Height"));
    mSize.Width = (float)Int32::Parse(worldElement->GetAttribute("Width"));

    // Read World Element
    {
        for each (XmlNode^ childNode in worldElement->ChildNodes)
        {
            if (childNode->NodeType == XmlNodeType::Element)
            {
                XmlElement^ childElement = (XmlElement^)childNode;

                if (childElement->Name == "Layer")
                {
                    try
                    {
                        // Create XmlSerializer for Layer
                        XmlSerializer^ serializer = gcnew XmlSerializer(HandBanana::Game::Layer::typeid);
                        
                        // Deserialize Layer Xml
                        Layer^ layer = (HandBanana::Game::Layer^)serializer->Deserialize(XmlReader::Create(gcnew StringReader(childElement->OuterXml)));

                        // Add Layer to List
                        mLayers.Add(layer->Name, layer);
                    }
                    catch (XmlException^ ex)
                    {
                        smLogger->ErrorException(L"Error reading Layer XML.", ex);
                    }
                } 
                else if (childElement->Name == "Monster")
                {
                    try 
                    {
                        Monster^ monster = Monster::Load(ResourceManager::GetObject(childElement->GetAttribute("Name")));
                        if (monster != nullptr)
                            mObjects.Add(childElement->GetAttribute("Name"), monster);
                    }
                    catch (XmlException^ ex)
                    {
                        smLogger->ErrorException(L"Error reading Monster XML.", ex);
                    }
                }
                else 
                {
                    throw gcnew XmlException("Unknown Element: \"" + childElement->Name + "\"");
                }
            }
        }
    }
    
    smLogger->Info("Loaded World: " + mName);
}

void World::WriteXml(XmlWriter^ argWriter)
{
    throw gcnew System::NotImplementedException();
}

XmlSchema^ World::GetSchema(void)
{
    return nullptr;
}

World^ World::Load(String^ argFile)
{
    World^ world = nullptr;
    try
    {    
        // Create XmlSerializer for World
        XmlSerializer^ serializer = gcnew XmlSerializer(World::typeid);
        
        // Deserializer World Xml
        world = (World^)serializer->Deserialize(gcnew FileStream(argFile, System::IO::FileMode::Open, System::IO::FileAccess::Read));
    } 
    catch (Exception^ ex)
    {
        smLogger->ErrorException(L"Error reading World XML.", ex);
    }

    return world;
}